
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package src;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 *
 * @author Mau
 */
public class Compiler {
    private boolean erroLexico;
    private boolean validToken;
    private char token;
    private int tokenPos;
    private int tokenPosTemp;
    private char []input;
    private int lineNumber;
    private String palavraChave;
    static private HashMap keywordsTable;
    
    static {
        keywordsTable = new HashMap();
        keywordsTable.put( "algoritmo", new Integer(Keywords.ALGORITMO) );
        keywordsTable.put( "fim_algoritmo", new Integer(Keywords.FIM_ALGORITMO) );
        keywordsTable.put( "declare", new Integer(Keywords.DECLARE) );
        keywordsTable.put( "literal", new Integer(Keywords.LITERAL) );
        keywordsTable.put( "inteiro", new Integer(Keywords.INTEIRO) );
        keywordsTable.put( "real", new Integer(Keywords.REAL) );
        keywordsTable.put( "logico", new Integer(Keywords.LOGICO) );
        keywordsTable.put( "leia", new Integer(Keywords.LEIA) );
        keywordsTable.put( "escreva", new Integer(Keywords.ESCREVA) );
        keywordsTable.put( "se", new Integer(Keywords.SE) );
        keywordsTable.put( "entao", new Integer(Keywords.ENTAO) );
        keywordsTable.put( "senao", new Integer(Keywords.SENAO) );
        keywordsTable.put( "fim_se", new Integer(Keywords.FIM_SE) );
        keywordsTable.put( "caso", new Integer(Keywords.CASO) );
        keywordsTable.put( "seja", new Integer(Keywords.SEJA) );
        keywordsTable.put( "fim_caso", new Integer(Keywords.FIM_CASO) );
        keywordsTable.put( "tipo", new Integer(Keywords.TIPO) );
        keywordsTable.put( "para", new Integer(Keywords.PARA) );
        keywordsTable.put( "verdadeiro", new Integer(Keywords.VERDADEIRO) );
        keywordsTable.put( "ate", new Integer(Keywords.ATE) );
        keywordsTable.put( "falso", new Integer(Keywords.FALSO) );
        keywordsTable.put( "faca", new Integer(Keywords.FACA) );
        keywordsTable.put( "retorne", new Integer(Keywords.RETORNE) );
        keywordsTable.put( "fim_para", new Integer(Keywords.FIM_PARA) );
        keywordsTable.put( "enquanto", new Integer(Keywords.ENQUANTO) );
        keywordsTable.put( "fim_enquanto", new Integer(Keywords.FIM_ENQUANTO) );
        keywordsTable.put( "procedimento", new Integer(Keywords.PROCEDIMENTO) );
        keywordsTable.put( "fim_procedimento", new Integer(Keywords.FIM_PROCEDIMENTO) );
        keywordsTable.put( "funcao", new Integer(Keywords.FUNCAO) );
        keywordsTable.put( "fim_funcao", new Integer(Keywords.FIM_FUNCAO) );
        keywordsTable.put( "ou", new Integer(Keywords.OU) );
        keywordsTable.put( "e", new Integer(Keywords.E) );
        keywordsTable.put( "nao", new Integer(Keywords.NAO) );
        keywordsTable.put( "registro", new Integer(Keywords.REGISTRO) );
        keywordsTable.put( "fim_registro", new Integer(Keywords.FIM_REGISTRO) );
        keywordsTable.put( "var", new Integer(Keywords.VAR) );
        keywordsTable.put( "constante", new Integer(Keywords.CONSTANTE) );
       
    }
        static private HashMap keysymbolsTable;
    
    static {
        keysymbolsTable = new HashMap();
        keysymbolsTable.put( ":", new Integer(Symbol.COLON) );
        keysymbolsTable.put( ",", new Integer(Symbol.COMMA) );
        keysymbolsTable.put( "^", new Integer(Symbol.CIRCUMFLEX) );
        keysymbolsTable.put( "(", new Integer(Symbol.LEFTPAR) );
        keysymbolsTable.put( ")", new Integer(Symbol.RIGHTPAR) );
        keysymbolsTable.put( "-", new Integer(Symbol.MINUS) );
        keysymbolsTable.put( "%", new Integer(Symbol.PERCENT) );
        keysymbolsTable.put( "*", new Integer(Symbol.MULT) );
        keysymbolsTable.put( "/", new Integer(Symbol.DIV) );
        keysymbolsTable.put( "+", new Integer(Symbol.PLUS) );
        keysymbolsTable.put( "&", new Integer(Symbol.AND) );
        keysymbolsTable.put( "=", new Integer(Symbol.EQ) );
        keysymbolsTable.put( "<", new Integer(Symbol.LT) );
        keysymbolsTable.put( ">", new Integer(Symbol.GT) );
        keysymbolsTable.put( ".", new Integer(Symbol.DOT) );
        keysymbolsTable.put( "[", new Integer(Symbol.LBRK) );
        keysymbolsTable.put( "]", new Integer(Symbol.RBRK) );
        keysymbolsTable.put( "<-", new Integer(Symbol.ATRIB) );
        keysymbolsTable.put( "<>", new Integer(Symbol.INEQ) );
        keysymbolsTable.put( "<=", new Integer(Symbol.LOET) );
        keysymbolsTable.put( ">=", new Integer(Symbol.GOET) );
        keysymbolsTable.put( "..", new Integer(Symbol.DBLEP) );
    }
    private PrintWriter writer;
    public void compile( char []p_input, String output ) throws FileNotFoundException, UnsupportedEncodingException {
        writer = new PrintWriter(output, "UTF-8");
        erroLexico = false;
        input = p_input;
        tokenPos = 0;
        lineNumber = 1;
        input[input.length - 1] = '\0';
        validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
        while(expr()==false){
            
        }
        
        if ( token != '\0' ) {
            error();
        }
        else if (erroLexico !=true){
            input = p_input;
        tokenPos = 0;
        lineNumber = 1;
        input[input.length - 1] = '\0';
        validToken = false;
        
             validToken = false;
            
            
                programa();
            
            
        }
        System.out.println("Fim da compilacao");
        writer.println("Fim da compilacao");
        writer.close();
    }
    
    private boolean nextToken() {
        // \t = tab -- ' '= espaço -- \r = carriage return
        while ( tokenPos < input.length && ( input[tokenPos] == ' ' || input[tokenPos] == '\r' || input[tokenPos] == '\t' || input[tokenPos] == '\n') ) {
            if(input[tokenPos] == '\n'){
                //System.out.println("Line number++");
                lineNumber++;
            }
            tokenPos++;
        }
        if ( tokenPos < input.length ) {
            token = input[tokenPos];
            if (token=='\0'){
                return true;
            }
            if(token == '{'){
                //achou comentario
                //System.out.println("COMENTS!");
                do{
                    token = input[tokenPos];
                    tokenPos++;
                }while (token != '}' &&  tokenPos < input.length);
                if(token != '}'){
                System.out.println("Linha "+lineNumber+": comentario nao fechado"); // transferir para metodo error posteriormente
                writer.println("Linha "+lineNumber+": comentario nao fechado");
                erroLexico = true;
                token = '\0';
                validToken = true;
                return true;
                }else{
                    //tokenPos++;
                    return false;
                }
            }
         return true;   
        }else {
            token = '\0';
        }
        /* Não funciona, aparentemente java trata { como um caracter especial.
        if(input[tokenPos] == '{'){
            System.out.println("COMMENTS!");
        }*/
       return true; 
    }
    
    private void nextChar(){
        if ( tokenPos < input.length ) {
            token = input[tokenPos];
            System.out.print(token);
          //  writer.print(token);
            tokenPos++;
        }
    }
    private void invalido(){
         System.out.println("Linha "+ lineNumber + ": " + token + " - simbolo nao identificado" );
            writer.println("Linha "+ lineNumber + ": " + token + " - simbolo nao identificado" );
            erroLexico = true;
            if ( tokenPos < input.length ) {
            token = input[tokenPos];
            
            tokenPos++;
        }
       
    }
    private boolean analyzeInvalid(){
        switch (token){
            case '@':
                invalido();
                
                return true;
            case '#':
                invalido();
                
                return true;
            case '\'':
                invalido();
                
                return true;
            case '?':
                invalido();
                
                return true;
            case '\\':
                invalido();
                
                return true;
            case '|':
                invalido();
                
                return true;
            case '!':
                invalido();
                
                return true;
            case '}':
                invalido();
                
                return true;
            default:
                return false;
            }
    }
    private boolean expr() {
        if (token =='\0'){
            return true;
        }
        if(tokenPos < input.length){
            
        if (analyzeInvalid()){
           validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
           return false;     
        }
            else
           if((token == '_' || Character.isLetter(token) || isKeySymbol()) && tokenPos< input.length){
            //System.out.println("Chamando método Identifier");
            
            
           if (analyzeKeySymbol()){
           validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
           return false;
       }
        else
       if (analyzeKeyword()){
           tokenPos = tokenPosTemp;
            validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
           return false;
       }
       else{
            analyzeIdentifier();
            return false;
       }
        }else{
            if(token == '\"'){
                //System.out.println("Chamando método Literal");
                nextChar();
                analyzeLiteral();
                return false;
            }else{
                if(Character.isDigit(token)){
                    //System.out.println("Chamando método Inteiro");
                    analyzeInt();
                    return false;
                }
                validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
                return false;
            }
        }
    }
        return true;
    }
    private boolean analyzeKeySymbol(){
        
        
        int palavra = tokenPos;
        palavraChave = "" + token;
        palavra++;
        
        if (palavra < input.length)
            palavraChave = palavraChave + input[palavra];
          
       if( keysymbolsTable.containsKey(palavraChave)){
           System.out.println(palavraChave +" - "+ palavraChave);
          // System.out.println();
           tokenPos = palavra;
        //   writer.println(palavraChave +" - "+ palavraChave);
           return true;
       }
       else if (keysymbolsTable.containsKey(palavraChave.substring(0,1))){
           System.out.println(token + " - " + token);
          // writer.println(token +" - "+ token);
           tokenPos++;
           return true;
       }
       return false;
        
    }
    private boolean isKeySymbol(){
        
        int palavra = tokenPos;
        palavraChave = "" + input[palavra];
        palavra++;
        if (palavra < input.length)
            palavraChave = palavraChave + input[palavra];
          
        
       if( keysymbolsTable.containsKey(palavraChave)){
           //System.out.println(palavraChave +" - "+ palavraChave);
          // System.out.println();
           tokenPosTemp = palavra;
           
           return true;
       }
       else if (keysymbolsTable.containsKey(palavraChave.substring(0,1))){
         //  System.out.println(token + " - " + token);
        //   tokenPos++;
           return true;
       }
       return false;
        
    }
    private boolean analyzeKeyword(){
        
        int palavra = tokenPos;
        palavraChave = "" + token;
        palavra++;
        while ((palavra < input.length) &&( Character.isLetter(input[palavra]) || input[palavra] =='_')){
            palavraChave = palavraChave + input[palavra];
            palavra++;
              
        }
         
       if( keywordsTable.containsKey(palavraChave)){
           System.out.println(palavraChave +" - "+ palavraChave);
          // System.out.println();
           tokenPosTemp = palavra;
           //writer.println(palavraChave +" - "+ palavraChave);
           return true;
       }
       return false;
        
    }
    private void analyzeIdentifier(){
        while((token == '_' || Character.isLetter(token) || Character.isDigit(token)) && !isKeySymbol()){
            nextChar();
        }
        System.out.println(" - Identifier");
        //writer.println(" - Identifier");
        
         validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
       // expr();
        /* 
         * Identificador : Sequência de letras, dígitos e o caractere '_' 
necessariamente iniciadas por letra ou '_'. Ex: abc, a12, _1, __a, 
___, A_2, AA
         */
    }
    private boolean isIdentifier(){
            if ((token != '_' && !Character.isLetter(token) && !Character.isDigit(token)) || isKeySymbol() || analyzeKeyword()){
                return false;
            }
        while((token == '_' || Character.isLetter(token) || Character.isDigit(token)) && !isKeySymbol()){
            nextChar();
        }
        System.out.println(" - Identifier");
        //writer.println(" - Identifier");
        
         validToken = false;
        while(  validToken==false){
        validToken = nextToken();
        }
        return true;
       // expr();
        /* 
         * Identificador : Sequência de letras, dígitos e o caractere '_' 
necessariamente iniciadas por letra ou '_'. Ex: abc, a12, _1, __a, 
___, A_2, AA
         */
    }
    private boolean analyzeLiteral(){
        
        do{ // espera por um outro " ou pelo fim do arquivo
            nextChar();
        }while(token != '\"' && tokenPos < input.length);
        
        if(token == '"'){
            System.out.println(" - Literal");
            //writer.println(" - Literal");
             validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
        return true;
        //    expr();
        }else{
            if(tokenPos == input.length-1){
                System.out.println("Fim de arquivo no literal");
                return false;
            }
            return true;
        }
        
        /*
         * cadeia_literal : Cadeia de caracteres entre aspas (” e ”) e sem 
mudança de linha. Ex: ”abc”, ”a@! 'oi' 3”
* 
*        manda ir analisando se chegar no final volta, avisa e chama expr de novo?
* 
         */
    }
    private boolean analyzeInt() {
        /*
         * numero_inteiro : Número inteiro sem sinal. Ex: 1, 2, 35, 0
         */
        while(Character.isDigit(token)){
            nextChar();
        }
        if(token == '.'){ // "virou real"! consome o '.' e daqui pra frente só podem ter numeros
            //System.out.println("Chamando método Real");
            nextChar();
            analyzeReal();
            return true;
        }
        else {
            //if(token)
            System.out.println(" - Inteiro");
            //writer.println(" - Inteiro");
             validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
         //   expr();
        return true;
         }
        
    }
    private boolean analyzeReal(){
        // O token chega aqui depois de ja ter passado pelo analyzeInt, i.e., só pode aceitar numeros
        while(Character.isDigit(token)){
            nextChar();
        }
        System.out.println(" - Real");
        //writer.println(" - Real");
         validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
        return true;
       // expr();
        
        /*
         * numero_real : Número real com ”.” entre dígitos e sem sinal. 
Ex: 1.2, 3.86, 0.0
         */
    }
  
    private void error() {
        if ( tokenPos == 0 ) {
            tokenPos = 1;
        }
        else
            if ( tokenPos >= input.length ) {
                tokenPos = input.length;
            }
        String strInput = new String( input,
        tokenPos - 1, input.length - tokenPos + 1 );
        String strError = "Error at \"" + strInput + "\"";
        //System.out.println( strError );
        // throws an exception - the program is terminated
        //throw new RuntimeException(strError);
        }
  
    
    //a partir daqui são as/os funções/métodos sintáticas/os!
  
    
    private void programa(){
            validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
        if(declaracoes()){
            if(analyzeKeyword()){
                if(palavraChave.equals("algoritmo")){
                    tokenPos = tokenPosTemp;
                    validToken = false;
        while( validToken==false){
        validToken = nextToken();
        }
                
        
            if(corpo()){
                if (analyzeKeyword()){
                    if(palavraChave.equals("fim_algoritmo")){
                   
                    }
                    else{
                    erroSintaticoPalavra();
                }
                }
                else{
                    erroSintaticoPalavra();
                }
            }
            else{
                erroSintaticoPalavra();
            }
            }
            else{
            erroSintaticoPalavra();
            }
          }        
        else{
          
        
         
        }
        } else{
           
        }
    
    }
   
    private void erroSintaticoPalavra(){
        
        if(analyzeKeyword()){
            
           System.out.println("Linha "+lineNumber+": erro sintatico proximo a " +palavraChave+"");
        writer.print("Linha "+lineNumber+": erro sintatico proximo a " +palavraChave+"");
        }
        else if(analyzeKeySymbol()){
            if (palavraChave=="\0"){
                palavraChave="EOF";
            }
           System.out.println("Linha "+lineNumber+": erro sintatico proximo a " +palavraChave+"");
        writer.print("Linha "+lineNumber+": erro sintatico proximo a " +palavraChave+"");
        }
        else{tokenPos++;
            if (tokenPos >= input.length){
                palavraChave="EOF";
                       System.out.println("Linha "+lineNumber+": erro sintatico proximo a " +palavraChave+"");
        writer.print("Linha "+lineNumber+": erro sintatico proximo a " +palavraChave+"");
        }
        
        }
    }
    
    
    //declaracoes -> = <decl_local_global> <declaracoes> | ε 
    private boolean declaracoes(){
        if (decl_local_global()){
            if(declaracoes()){
                return true;
            }
            else{
                return false;
            }
        }
        else{
//                        validToken = false;
//        while( validToken==false){
//        validToken = nextToken();
//        }
        return true;
        }
    }
    
    
    
    private boolean decl_local_global(){
        if(declaracao_local()){
            return true;
        }
        else if (declaracao_global()){
            return true;
        }
        return false;
    }
    
    
    public boolean declaracao_local(){
        if(analyzeKeyword()){
            if(palavraChave.equals("declare")){
                tokenPos = tokenPosTemp;
                validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                    }
                if(variavel()){
                    return true;
                }
                else{
                    return false;
                }
                
            }
           if(palavraChave.equals("constante")){
               tokenPos = tokenPosTemp;
               if(!isIdentifier()){
                    return false;
                }
                else{
                   
                    validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                    }
                    if(token ==':'){
                        tokenPos++;
                        validToken = false;
                        while( validToken==false){
                            validToken = nextToken();
                        
                        }
                     if(!tipo_basico()){
                         return false;
                     }
                         validToken = false;
                        while( validToken==false){
                            validToken = nextToken();
                        
                        }
                        if(token=='='){
                            tokenPos++;
                        validToken = false;
                        while( validToken==false){
                            validToken = nextToken();
                        
                        }
                        if (valor_constante()){
                            return true;
                        }
                        else{
                            return false;
                        }
                        
                         
                         
                     }
                        else{
                            return false;
                        }
                       
                        
                    }
                    else{
                        return false;
                    }
                
                }
           }
           else if(analyzeKeyword()){
                      if(!palavraChave.equals( "tipo")){
                      
                    return false;
                }
                else{
                   
                    validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                    }
                    if(token ==':'){
                        tokenPos++;
                        validToken = false;
                        while( validToken==false){
                            validToken = nextToken();
                        
                        }
                        if (tipo()){
                            return true;
                        }
                        else{
                            return false;
                        }
                    }
                    else{
                        return false;
                    }
                      }
           }
           else{
               return false;
           }
        }else{
            return false;
        }
    }
    
    private boolean variavel(){
        if (identificador()){
            validToken = false;
            while( validToken==false){
                validToken = nextToken();
                        
            }
           if(mais_ident()){
               validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                    }
                    if(isKeySymbol() ){
                        if(token == ':'){
                            tokenPos++;
                        validToken = false;
                        while( validToken==false){
                            validToken = nextToken();
                        
                        }
                        
                    if(tipo()){
                        return true;
                    }
                    else{
                        return false;
                    }
                    }
                    else{
                        return false;
                    }
                    } else return false;
        }
        else{
        
        return false;
        }
    }
        else{
            return false;
        }
    }
    
    private boolean identificador(){
       if(ponteiro_opcional()){
           if(isIdentifier()){
               if(outros_ident()){
                   if(dimensao()){
                       return true;
                   }
                   else{
                       return false;
                   }
               }else{
                   return false;
               }
           }
           else{
               return false;
           }
       }
       else{
        return false;
       }
    }
    
    private boolean dimensao(){
        if (token == '['){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if (exp_aritmetica()){
                if (token == ']'){
                    tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if (dimensao()){
                return true;
            }
            else{
                return false;
            }
            }
                else{
                    return false;
                }
            }
            else{
                return false;
            }
            
    }
        // [ <exp_aritmetica> ] <dimensao>| ε
        return true;
    }
    
    private boolean exp_aritmetica(){
        if (termo()){
            if(outros_termos()){
                return true;
            }
        }
        //<termo> <outros_termos>
        return false;
    }
    private boolean termo(){
        if(fator()){
            if(outros_fatores()){
                return true;
            }
        }
        //<fator> <outros_fatores>
        return false;
    }
    private boolean op_multiplicacao(){
        if(token=='*'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            return true;
        }
        else if(token=='/'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            return true;
        }
      return false;   
        
        //* | /
    }
    private boolean outros_fatores(){
        if (op_multiplicacao()){
            if(fator()){
                if(outros_fatores()){
                    return true;
                }
            }
            return false;
        }
        return true;
        //<op_multiplicacao> <fator> <outros_fatores> | ε
    }
    private boolean fator(){
        if(parcela()){
            if(outras_parcelas()){
                return true;
            }
        }
        return false;
        //<parcela> <outras_parcelas>
    }
    private boolean parcela(){
        if (op_unario()){
            if (parcela_unario()){
                return true;
            }
           
        }
         if(parcela_nao_unario()){
            return true;
        }
        return false;
        //<op_unario> <parcela_unario> | <parcela_nao_unario>
    }
    private boolean parcela_nao_unario(){
        if (token=='&'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if(isIdentifier()){
                if(outros_ident()){
                    if(dimensao()){
                        
                        return true;
                    }
                }
            }
        }
        else if(token=='\"'){
            nextChar();
            if(analyzeLiteral()){
            
            return true;
            }
        }
        return false;
        //& IDENT <outros_ident> <dimensao> | CADEIA
    }
    private boolean parcela_unario(){
        if (token=='^'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if(isIdentifier()){
                if(outros_ident()){
                    if(dimensao()){
                        return true;
                    }
                }
            }
        }
        else if(isIdentifier()){
            if(chamada_partes()){
                return true;
            }
            
        }
        else if(Character.isDigit(token)){
            if (analyzeInt()){
                return true;
            }
            else{
                return true;
            }
            
        }
        else if(token=='('){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if (expressao()){
                if(token==')'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            return true;
            }
        }
        }
        //^ IDENT <outros_ident> <dimensao> | IDENT <chamada_partes> | NUM_INT | NUM_REAL | ( <expressao> )
        
        return false;
    }
    private boolean chamada_partes(){
        if (token=='('){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            
            }
            if(expressao()){
                if(mais_expressao()){
                   if (token==')'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            
            }
            return true;
                }
            } 
        }
            return false;
        }
        if(outros_ident()){
            if(dimensao()){
                return true;
            }
        }
        //( <expressao> <mais_expressao> ) | <outros_ident> <dimensao> | ε
            return true;
    }
    private boolean outras_parcelas(){
        if (token=='%'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if (parcela()){
                if (outras_parcelas()){
                    return true;
                }
            }
            return false;
        }
        return true;
        //% <parcela> <outras_parcelas> | ε
    }
    private boolean op_adicao(){
        if (token=='+' || token =='-'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            return true;
        }
        return false;
        //+ | -
    }
    private boolean outros_termos(){
        if(op_adicao()){
            if(termo()){
            if(outros_termos()){
                return true;
            }
            }
            return false;
        }
        //<op_adicao> <termo> <outros_termos> | ε
        
        return true;
    }
    private boolean outros_ident(){
        if(token=='.'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if(isIdentifier()){
                if(outros_ident()){
                    
                }
                else{
                    return false;
                }
            }
            else{
                return false;
            }
        
    }
        return true;
    }
    
    private boolean ponteiro_opcional(){
        if(token=='^'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
        }
        
        return true;
    }
    
    private boolean mais_variaveis(){
        if (variavel()){
            if(mais_variaveis()){
                return true;
            }
            else{
                return false;
            }
        }
        // <variavel> <mais_variaveis> | ε
        
        return true;
    }
    
    private boolean mais_ident(){
        if (token ==','){
            tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if(identificador()){
                if(mais_ident()){
                    return true;
                }
                else{
                    return false;
                }
            }
            else{
                return false;
            }
        }
        // , <identificador> <mais_ident> | ε
        return true;
    }
    
    private boolean valor_constante(){
        palavraChave = "";
        if(analyzeKeyword()){
            if(palavraChave.equals("verdadeiro") || palavraChave.equals("falso")){
                tokenPos = tokenPosTemp;
                validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
                return true;
            }
            else{
                return false;
            }
        }else
        if(token == '"'){
            tokenPos++;
                //System.out.println("Chamando método Literal");
                nextChar();
                if(analyzeLiteral()){
                    return true;
                }
                
            }else
                if(Character.isDigit(token)){
                    //System.out.println("Chamando método Inteiro");
                    if(analyzeInt()){
                        return true;
                    }
                }
                
        //CADEIA | NUM_INT | NUM_REAL | verdadeiro | falso
        return false;
    }
      
    private boolean tipo_basico(){
        palavraChave = "";
        analyzeKeyword();
        
        switch (palavraChave){
            case "literal":
            case "inteiro":
            case "real":
            case "logico":
                tokenPos= tokenPosTemp;
                validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
                return true;
            default:
                return false;
        }
        
        //literal | inteiro | real | logico
        
    }
    
    private boolean tipo(){
        if (registro()){
            return true;
        }
        else if(tipo_estendido()){
            return true;
        }
    
        return false;
    }                   
    
    private boolean registro(){
        if (variavel()){
            if (mais_variaveis()){
                if (analyzeKeyword()){
                    if (palavraChave.equals("fim_registro")){
                        tokenPos = tokenPosTemp;
                        validToken = false;
                        while( validToken==false){
                            validToken = nextToken();
                        
                        }
                        return true;
                    }
                }
            
            }
            
        }
        //registro <variavel> <mais_variaveis> fim_registro
        return false;
    }
    
    private boolean tipo_estendido(){
        if(ponteiro_opcional()){
            if(tipo_basico_ident()){
                return true;
            }
            
            
        }
        //<ponteiro_opcional> <tipo_basico_ident>
        return false;
    }
    
    private boolean parametros_opcional(){
        if(parametro()){
            return true;
        }
        //<parametro> | ε
        return true;
    }
    private boolean parametro(){
        if (var_opcional()){
            if (identificador()){
                if(mais_ident()){
                   if (token ==':'){
                       tokenPos++;
            validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            if (tipo_estendido()){
                if(mais_parametros()){
                    return true;
                }
            }
                }
            }
        }
        }
        //<var_opcional> <identificador> <mais_ident> : <tipo_estendido> <mais_parametros>
        return false;
    }
    
    
    private boolean mais_parametros(){
        if (token ==','){
            tokenPos++;
            validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
            if (parametro()){
                return true;
            }
            return false;
        }
        //, <parametro> | ε
        return true;
    }
    private boolean var_opcional(){
        if (analyzeKeyword()){
            if (palavraChave.equals("var")){
                tokenPos = tokenPosTemp;
                 validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
                return true;
            }
        }
        //var | ε
        return true;
    }
    private boolean declaracoes_locais(){
        if (declaracao_local()){
            if (declaracoes_locais())
                return true;
            return false;
        }
        //<declaracao_local> <declaracoes_locais> | ε
        return true;
    }
    
    private boolean comandos(){
        if(cmd()){
            if(comandos()){
                return true;
            }
            else{
                return false;
            }
        }
        return true;
    }
    
    private boolean cmd(){
        if (analyzeKeyword()){
            switch (palavraChave){
                case "leia":
                    tokenPos=tokenPosTemp;
                    validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                    if (token == '('){
                        tokenPos++;
                        validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                    if (identificador()){
                        if (mais_ident()){
                            if (token ==')'){
                                tokenPos++;
                               validToken = false;
                                while( validToken==false){
                                validToken = nextToken();
                        
                                } 
                                return true;
                            }
                            else return false;
                            
                        }
                        else return false;
                    }
                    else{
                        return false;
                    }
                    }
                    else return false;
      
                    
                    
                    
                case "escreva":
                    tokenPos=tokenPosTemp;
                    validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                    if (token == '('){
                        tokenPos++;
                        validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                    if (expressao()){
                        if (mais_expressao()){
                            if (token ==')'){
                                tokenPos++;
                               validToken = false;
                                while( validToken==false){
                                validToken = nextToken();
                        
                                } 
                                return true;
                            }return false;
                            
                            
                        }
                        else return false;
                    } else return false;
            }
                    
                case "se":
                    tokenPos=tokenPosTemp;
                validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                if (expressao()){
                    if(analyzeKeyword()){
                        if (palavraChave.equals("entao")){
                            tokenPos = tokenPosTemp;
                            validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        }
                    if (comandos()){
                        if (senao_opcional()){
                            if (analyzeKeyword()){
                                if (palavraChave.equals("fim_se")){
                                    tokenPos = tokenPosTemp;
                                         validToken = false;
                                    while( validToken==false){
                                        validToken = nextToken();
                                    }    
                                
                                    return true;
                                } else return false;
                            }else return false;
                        }
                        
                    }else return false;
                    } else return false;
                } else return false;
               }else return false;
               case  "caso":
                   tokenPos=tokenPosTemp;
                 validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                   if (exp_aritmetica()){
                       if (analyzeKeyword()){
                           if (palavraChave.equals("seja")){
                               tokenPos = tokenPosTemp;
                               validToken = false;
                               while( validToken==false){
                                 validToken = nextToken();
                        
                               }
                               if (selecao()){
                                  if (senao_opcional()){
                                      if (analyzeKeyword()){
                                if (palavraChave.equals("fim_caso")){
                                    tokenPos = tokenPosTemp;
                                         validToken = false;
                                    while( validToken==false){
                                        validToken = nextToken();
                                    }    
                                
                                    return true;
                                } else return false;
                            }else return false;
                                  } 
                               }
                           } else return false;
                       } else return false;
                   } else return false;
               case "para":
                   tokenPos=tokenPosTemp;
                   validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                   if (isIdentifier()){
                       if (isKeySymbol()){
                           if(palavraChave.equals("<-")){
                               tokenPos = tokenPosTemp;
                               validToken = false;
                                    while( validToken==false){
                                        validToken = nextToken();
                                    }  
                             if (exp_aritmetica()){
                                 if(analyzeKeyword()){
                                     if(palavraChave.equals("ate")){
                                         tokenPos = tokenPosTemp;
                                        validToken = false;
                                        while( validToken==false){
                                            validToken = nextToken();
                                        }
                                        if (exp_aritmetica()){
                                            if(analyzeKeyword()){
                                     if(palavraChave.equals("faca")){
                                         tokenPos = tokenPosTemp;
                                        validToken = false;
                                        while( validToken==false){
                                            validToken = nextToken();
                                        }
                                        if (comandos()){
                                            if (exp_aritmetica()){
                                            if(analyzeKeyword()){
                                     if(palavraChave.equals("fim_para")){
                                         tokenPos = tokenPosTemp;
                                        validToken = false;
                                        while( validToken==false){
                                            validToken = nextToken();
                                            
                                        }
                                        return true;
                                        }
                                        }
                                        else return false;
                                        
                                          }
                                       }
                                            }  
                                        }
                                        }
                                     }
                                 }
                             }
                           }
                       }
                   }
                   return false;
                   
                   
        
               case "enquanto":
                tokenPos=tokenPosTemp;
                   validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                if (expressao()){
                    if(analyzeKeyword()){
                        if (palavraChave.equals("faca")){
                            validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        }
                    if (comandos()){
                        
                            if (analyzeKeyword()){
                                if (palavraChave.equals("fim_enquanto")){
                                         validToken = false;
                                    while( validToken==false){
                                        validToken = nextToken();
                                    }    
                                
                                    return true;
                                } else return false;
                            }else return false;
                        
                        
                    }else return false;
                    } else return false;
                } else return false;
               }else return false;   
                   
               case "faca":
                  tokenPos=tokenPosTemp;
                   validToken = false;
                    while( validToken==false){
                        validToken = nextToken();
                        
                    }
                   if (comandos()){
                       if (analyzeKeyword()){
                                if (palavraChave.equals("ate")){
                                         validToken = false;
                                    while( validToken==false){
                                        validToken = nextToken();
                                    }
                                    if (expressao()){
                                        return true;
                                    }
                   }
                       }
               }
                   return false;
               
            }
        }
        else if(token == '^'){
            tokenPos++;
            validToken = false;
            while( validToken==false){
                                        validToken = nextToken();
            }
            if (isIdentifier()){
                if (outros_ident()){
                    if (dimensao()){
                        if(analyzeKeySymbol()){
                            if(palavraChave.equals("<-")){
                                validToken = false;
                                    while( validToken==false){
                                        validToken = nextToken();
                                    }
                               if (expressao()){
                                   return true;
                               }     
                            }
                        }
                    }
                }
            }
            else return false;
        }
        else if(isIdentifier()){
            if (chamada_atribuicao()){
                return true;
            }
        }
        else if(analyzeKeyword()){
            if (palavraChave.equals("retorne")){
                validToken = false;
                                    while( validToken==false){
                                        validToken = nextToken();
                                    }
                if (expressao()){
                    return true;
                }
            }
        }
        /*= leia ( <identificador> <mais_ident> )
 | escreva ( <expressao> <mais_expressao> )
 | se <expressao> entao <comandos> <senao_opcional> fim_se 
 | caso <exp_aritmetica> seja <selecao> <senao_opcional> fim_caso
 | para IDENT <- <exp_aritmetica> ate <exp_aritmetica> faca <comandos> fim_para
 | enquanto <expressao> faca <comandos> fim_enquanto
 | faca <comandos> ate <expressao>
 | ^ IDENT <outros_ident> <dimensao> <- <expressao>
 | IDENT <chamada_atribuicao>
 | retorne <expressao>
 * */
        return false;
    }
    private boolean chamada_atribuicao(){
    if(token == '(')
    {
        tokenPos++;
        validToken=false;
         while( validToken==false){
            validToken = nextToken();
        }
        if(expressao())
        {
            if(mais_expressao())
            {
                if(token == ')'){
                    tokenPos++;
                     return true;
                }else
                {
                    return false;
                }                    
            }
            else{
                return false;
            }
        }
        else{
            return false;
        }           
    }
    else{            
        if (outros_ident()){
             if (dimensao()){
                 if(analyzeKeySymbol()){
                     if(palavraChave.equals("<-")){
                         
                         validToken = false;
                             while( validToken==false){
                                 validToken = nextToken();
                             }
                        if (expressao()){
                            return true;
                        }     
                     }
                 }
             }
        }
    }
    
    return false;        
}
private boolean selecao(){
    if(constantes())
    {
        if(token == ':')
        {
            tokenPos++;
            validToken = false;
            while(validToken == false){
                validToken = nextToken();                        
            }
            if(comandos()){
                if(mais_selecao()){
                    return true;
                }
            }
        }           
    }
    return false;
}
private boolean mais_selecao(){
    if(selecao())
    {
        return true;
    }
    return true;
}
private boolean constantes(){
    if(numero_intervalo()){
        if(mais_constantes()){
            return true;
        }
    }
    return false;
}
private boolean mais_constantes(){
    if (token ==','){
        tokenPos++;
        validToken = false;
        while( validToken==false){
          validToken = nextToken();
                    
        }
        if(constantes()){
            return true;
        }
        else{
            return false;
        }
    }
    // , <expressao> <mais_expressao> | ε
    return true;
}
private boolean numero_intervalo(){
    if(op_unario())
    {            
        if(Character.isDigit(token)){
            //System.out.println("Chamando método Inteiro");
            if(analyzeInt()){
                if(intervalo_opcional()){
                    return true;
                }                    
            }
        }            
    }
    return true;
}
private boolean op_unario(){
    if (token=='-'){
        tokenPos++;
            validToken = false;
            while(validToken == false){
                validToken = nextToken();                        
            }
            
    }
    return true;
}
private boolean intervalo_opcional(){
    if (isKeySymbol()){
        if (palavraChave.equals("..")){
            if (op_unario()){
                if(analyzeInt()){
                    return true;
                }
            }
            return false;
        }
        
    }
    
    return true;
}
    private boolean senao_opcional(){
        if (analyzeKeyword()){
            if (palavraChave.equals("senao")){
                if (comandos()){
                    return true;
                }
           return false;
            }
            
        }
        //senao <comandos> | ε
        return true;
    }
    private boolean mais_expressao(){
        if (token == ','){
            tokenPos++;
            validToken = false;
        while( validToken==false){
          validToken = nextToken();
                    
        }
            if (expressao()){
                if (mais_expressao()){
                    return true;
                }
            }
           return false;
        }
        //, <expressao> <mais_expressao> | ε
        return true;
    }
    private boolean expressao(){
        if (termo_logico()){
            if (outros_termos_logicos()){
                return true;
            }
            return false;
        }
        
        return false;
    }
    private boolean termo_logico(){
        if (fator_logico()){
            if (outros_fatores_logicos()){
                return true;
            }
        }
      
        return false;
    }
    private boolean fator_logico(){
        if (op_nao()){
            if(parcela_logica()){
                return true;
            }
        }
        //<op_nao> <parcela_logica>
        return false;
    }
private boolean op_nao(){
   	if (analyzeKeyword()){
        if (palavraChave.equals("nao")){
            tokenPos = tokenPosTemp;
             validToken = false;
        while( validToken==false){
          validToken = nextToken();
                    
        }
            return true;
        }
    }
    //nao | ε
    return true;
}

private boolean parcela_logica(){
   	if(analyzeKeyword()){
            if(palavraChave.equals("verdadeiro") || palavraChave.equals("falso")){
                tokenPos = tokenPosTemp;
                validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
                return true;
            }
            else{
                return false;
            }
    }else{
       	if(exp_relacional()){
           	return true;
       	}
   	}
    return false;
}
private boolean exp_relacional()
{
    if(exp_aritmetica())
    {
        if(op_opcional())
        {
            return true;
        }           
    }
    
    return false;
    //<exp_relacional> ::= <exp_aritmetica> <op_opcional>
}
private boolean op_relacional(){
    if(isKeySymbol())
    {
        if(palavraChave == "=" || palavraChave == "<>" || palavraChave == "<="|| palavraChave == ">=" || palavraChave == "<" || palavraChave == ">"){
            return true;
        }            
    }
    return false;
}
private boolean op_opcional(){
    if(op_relacional())
    {
        if(exp_aritmetica())
        {
            return true;
        }
    }
    //<op_relacional> <exp_aritmetica> | ε
    return true;
}
private boolean outros_termos_logicos(){
    if(analyzeKeyword())
    {
    	if(palavraChave.equals("ou"))
    	{
            tokenPos = tokenPosTemp;
             validToken = false;
        while( validToken==false){
          validToken = nextToken();
                    
        }
    		if(termo_logico())
    		{
    			if(outros_termos_logicos())
    			{
    				return true;
    			}
    		}
    	}
    }
    return true;
}
private boolean outros_fatores_logicos(){
    if(analyzeKeyword())
    {
    	if(palavraChave.equals("e"))
    	{
            tokenPos = tokenPosTemp;
             validToken = false;
        while( validToken==false){
          validToken = nextToken();
                    
        }
    		if(fator_logico())
    		{
    			if(outros_fatores_logicos())
    			{
    				return true;
    			}
    		}
    	}
    }
    return true;
}
    private boolean declaracao_global(){
        if(analyzeKeyword()){
            if (palavraChave.equals("procedimento")){
                tokenPos = tokenPosTemp;
                validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
            }
                if (isIdentifier()){
                    if(token == '('){
                        tokenPos++;
                        validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
                        if(parametros_opcional()){
                             if (isIdentifier()){
                                 if(token == ')'){
                                     tokenPos++;
                                      validToken = false;
                                       while( validToken==false){
                                      validToken = nextToken();
                        
                                         }
                            if (declaracoes_locais()){
                                if(comandos()){
                                    if(analyzeKeyword()){
                                        if (palavraChave.equals("fim_procedimento")){
                                            tokenPos = tokenPosTemp;
                                            return true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
                }
            }
            else{
            if (palavraChave.equals("funcao")){
                tokenPos = tokenPosTemp;
                validToken = false;
            while( validToken==false){
              validToken = nextToken();
                if (isIdentifier()){
                    if(token == '('){
                        tokenPos++;
                        validToken = false;
            while( validToken==false){
              validToken = nextToken();
                        
            }
                        if(parametros_opcional()){
                             if (isIdentifier()){
                                 if(token == ')'){
                                     tokenPos++;
                                      validToken = false;
                                       while( validToken==false){
                                      validToken = nextToken();
                        
                                         }
                                   if(token == ':'){
                                       tokenPos++;
                                      validToken = false;
                                       while( validToken==false){
                                      validToken = nextToken();
                        
                                         }
                             if (tipo_estendido()){          
                            if (declaracoes_locais()){
                                if(comandos()){
                                    if(analyzeKeyword()){
                                        if (palavraChave.equals("fim_funcao")){
                                            tokenPos = tokenPosTemp;
                                            return true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
                }
                    }
                }
            }
            
        }
        }
        // procedimento IDENT ( <parametros_opcional> ) <declaracoes_locais> <comandos> fim_procedimento
        // | funcao IDENT ( <parametros_opcional> ) : <tipo_estendido> <declaracoes_locais> <comandos> fim_funcao

        return false;
    }
    
    
    private boolean corpo(){
        if (declaracoes_locais()){
            if (comandos()){
                return true;
            }
            return false;
        }
      

        return false;
    }
    
    private boolean tipo_basico_ident(){
        if(tipo_basico()){
            return true;
        }
        else if(isIdentifier()){
            return true;
        }
       
        return false;
    }
}
